CPU network SoA: heap-free weights (index ABI, packing A) - #3826
Open
nrnhines wants to merge 34 commits into
Open
CPU network SoA: heap-free weights (index ABI, packing A)#3826nrnhines wants to merge 34 commits into
nrnhines wants to merge 34 commits into
Conversation
Documents the decision to pause GPU network buffers until CPU network SoA adoption. Provides agent rules, session starting prompt, and Phase 0 design checklist for local/cpu-network-soa branched from master.
Expand doc/network-soa-phase0.md into the authoritative field-tag, handle, thread-slice, sidecar, and invalidation spec. Add neuron::container::network PointProcess and Weight soa storages on Model (Node-style handles), wire find_container_info/unsorted callbacks, and unit-test that handles survive permutation.
Add §5.4.1 (target_/src_ as indices/handles, not data_handle) and §5.5.1 (InputPreSyn deferred; thin gid→fanout after cpu-net-soa).
Embed PointProcess::owning_handle on Point_process and sync Instance/ MechType/ThreadId when prop or _vnt changes. NetCon allocates parallel Weight SoA rows (heap weight_ stays delivery primary). Unit tests cover dual-write helpers and PP shell lifetime.
Add network::NetCon storage (Target, WeightIndex, WeightCount, Delay, Active, SrcPreSyn) on Model. NetCon owns an SoA row and syncs fields on create/update. HOC weight() steers into Weight SoA data_handles; deliver mirrors SoA↔heap around pnt_receive so NET_RECEIVE still sees double*.
Add network::PreSyn storage on Model and embed owning handles on PreSyn. Rebuild a global NetCon* fanout order from dil_ (CoreNEURON-shaped ranges); send/deliver/fanout iterate that order with dil_ fallback. NetCon::SrcPreSyn points at the source PreSyn SoA row.
SelfEvent records Weight SoA base index and PointProcess row; net_send resolves index from NetCon. Delivery uses nrn_pnt_receive_by_weight_index (M2: SoA→heap→MOD pnt_receive→heap→SoA). NetCon::deliver shares that path.
…ght wipe Document Phases 0–4 status and known gaps in GROK-NETWORK-SOA.md. Rebuild PreSyn fanout at NetCvode::init_events (not only on first spike). Stop soa_sync from copying heap weights over SoA (HOC weight writes). Add pytest/ctest network_soa_delivery gate for NetStim→ExpSyn.
MOD/nrnivmodl builds only see build/include. Embedding PointProcess owning_handle forced network/model_data headers that are not installed there, breaking demo release compiles. Store a non-owning _soa_id on Point_process; own the SoA row via a map in point.cpp. Add point_process_access.hpp / nrn_point_process_soa_row for library code.
HOC weight[] is SoA-primary; pnt_receive_init and FOR_NETCONS mutate the heap. Sync SoA↔heap around INITIAL, and for FOR_NETCONS targets sync all NetCons sharing the target (including WatchCondition flag delivery). Fixes hoctests::test_netrec_init_py and external_nrntest FOR_NETCONS/stdp1.
…eliver Include PointProcess, Weight, NetCon, and PreSyn containers in nrn_ensure_model_data_are_sorted (thread partition, weight-block repack, fanout rebuild, cache offsets). On NetCon deliver without FOR_NETCONS, pass a temporary buffer into pnt_receive instead of the long-lived weight_ heap so SoA stays the source of truth while the heap remains for SaveState and FOR_NETCONS.
Save NetCon weights from Weight SoA (HOC-primary) and restore into both heap and SoA so materialize-on-deliver matches SaveState. Resolve SelfEvent ownership via NetCon object index and weight_index2netcon when the heap pointer is absent; index2netcon maps all NetCons by HOC index.
Materialize Weight SoA into the heap before BBSaveState weight IO and mirror heap back to SoA after restore. Match SelfEvents to target NetCons by heap base or weight_index, and rebind both fields from the DEList ncindex on restore (same dual-write policy as SaveState).
sort_network_data must resolve HOC point-process objects via ob2pntproc_0 (dataspace), not this_pointer. NetCon deliver must pass the long-lived weight_ heap into pnt_receive so MOD net_send(..., _w) preserves SelfEvent identity for SaveState; resolve owner by weight_index when needed. Softens SelfEvent savestate_write when no NetCon is found.
Add doc/network-soa/ with L0 README, topology (fanout authority, CoreNEURON mapping), dual-write/heap roadmap, and sort packing. Point GROK handoff at the layered map and correct stale short-lived-materialize status text.
Sync Weight SoA when exporting NetCon weights to CoreNEURON and when returning weights after a CoreNEURON run (HOC weight[] is SoA-primary). Apply black/clang-format line-wrap fixes for network SoA tests. Merge with master already on branch for formatting toolchain updates.
SelfEvent from mech INITIAL often has nullptr weight; still route through nrn_pnt_receive_by_weight_index so FOR_NETCONS heap mutations sync to SoA. Apply ninja format-pr clang-format fixes for network SoA sources.
ASan CI: nrn_point_process_soa_sync during free_one_point/relocate read freed Prop or dangling state. Stop syncing on free (SoA row released in ~Point_process); harden sync to verify prop still owns this pnt and that _vnt is a live NrnThread. NetCon factory wrote magnitude only to weight_ heap; HOC weight[] reads SoA and init_events soa_to_heap wiped the value (0.0 != 0.1). Mirror magnitude into Weight SoA after construction.
Do not invent a short-lived weight buffer when weight_index < 0 (flag-only / INITIAL net_send); MOD may net_send that pointer and corrupt later queue / BBSaveState handling. Skip NET_RECEIVE INITIAL for NetCons whose target Prop is already freed.
Branch-only follow-on to dual-write PR tip. Record settled heap-free policy (O(1) weight block, packing A, queue clear on structure change, indices in bulk tables). Add weight_index_t/netcon_index_t and wire NetCon SoA WeightIndex/WeightCount to them.
Replace in-shell vector of Weight owning handles with an off-shell WeightBlock (unique_ptr). NetCon SoA WeightIndex/WeightCount are the authority for the base; HOC weight[i] uses a stable data_handle from the block. Dual-write weight_ heap remains for MOD until a later step. sizeof(NetCon) 104 -> 88 on this platform.
Replace g_network_fanout_order vector<NetCon*> with vector<netcon_index_t> (SoA rows). Rebuild g_netcon_by_soa_row for O(1) shell resolve on deliver. PreSyn NcIndex/NcCount use the compact index types. dil_ remains the rebuild source and mid-update fallback. Unit tests cover index width and resolve model.
nocmodl emits walks over weight bases via _nrn_netcon_weight_bases and _nrn_fornetcon_weight (resolve base to dual-write weight_ heap). ForNetConsInfo stores both bases and legacy double** argslist. Sort packs NetCon/weights by target PP SoA row after thread (packing A) for peer locality.
Non-FOR_NETCONS pnt_receive materializes Weight SoA into a thread-local buffer and writes back after MOD. TLS active weight_index binds net_send SelfEvents so scratch pointers are never queued. FOR_NETCONS still uses long-lived weight_ heaps until step 6. nrn_net_send only retains weight_ when it is a known NetCon heap base.
Weight SoA is sole storage for edge weights. Non-FOR_NETCONS deliver uses thread-local scratch; FOR_NETCONS owns per-target scratch buffers keyed by weight bases. weight_soa_data() exposes contiguous SoA doubles for legacy APIs (BBSS, CoreNEURON export, nrn_netcon_weight). SelfEvent identity is weight_index only. sizeof(NetCon) 80 on this platform.
Capture sim vs edit epochs: CoreNEURON-shaped hot path plus packing A and reconfigurable nthread; full NEURON construction between runs. Mark steps 1–6 done; outline 6b zero-copy and 7 nocmodl index ABI as the next phase.
Prefer data_if_contiguous() / weight_soa_data() for non-FOR_NETCONS deliver and NET_RECEIVE INITIAL so MOD writes SoA in place. TLS materialize remains only when the block is scattered (post-erase, pre-sort). SelfEvent identity stays weight_index. Unit test covers contiguous zero-copy writes.
Change pnt_receive_t and pnt_receive_init_t to (Point_process*, int weight_index, double flag). Generated NET_RECEIVE (nocmodl + NMODL neuron) keeps _args[i] via _nrn_netrec_wsoa / _nrn_netrec_wsoa_done; net_send / artcell_net_send take the SoA base index (−1 if none). Always commit wsoa_done so NET_RECEIVE INITIAL values reach Weight SoA when fornetcon_prepare has already mapped FOR_NETCONS scratch. Verified: build 225/225, build-asan 223/223.
ForNetConsInfo now holds only Weight SoA base indices. Generated FOR_NETCONS resolves each peer via _nrn_fornetcon_weight: zero-copy into a contiguous SoA block when packed, otherwise a shared TLS view committed on the next peer or at receive end. Removes argslist, weight_storage, and the base→buf map; receive path no longer bulk- syncs a per-target double pool. Verified: build 225/225, build-asan 223/223.
Remove SelfEvent::weight_ (queue identity is weight_index only) and _nrn_netcon_args (bases + _nrn_fornetcon_weight only). TLS commit on _nrn_netrec_wsoa_done only when the primary edge used materialize; zero-copy SoA needs no writeback. Document post-7a–7c host path shape. Verified: build 225/225, build-asan 223/223.
|
✔️ 9eebc43 -> Azure artifacts URL |
|
✔️ 9eebc43 -> Azure artifacts URL |
nrnhines
added a commit
that referenced
this pull request
Jul 25, 2026
Point handoff at local/gpu-native-net-soa (PR #3826 base + gpu-native merge). Record baseline parity @ 0.025/1.0, unpause Stages 2–3 with weight_index ABI constraints, and replace obsolete post_solve open-bug starting prompt.
Sim path was looking up NetCon* from weight_index on every NET_RECEIVE (_nrn_netrec_wsoa / FOR_NETCONS), which is CoreNEURON-unlike and O(N) over HOC NetCons — Traub 1/10 hung after first spikes until nrn_timeout. Address model().weights()[base] directly (weight_soa_ptr), TLS materialize only if out of range. Remove weight_index2netcon; NetCon→base stays forward-only (owning handles / WeightIndex on sort). SaveState SelfEvent write uses a cold O(N) scan for HOC object index only. Verified: Traub one_tenth no-gap, nthread=1, pc.timeout(1); 100 ms nocmodl and NMODL both complete with exact 4474 spikes.
Classic nrnivmodl did not export NMODL_PYLIB or NMODLHOME, so nmodl aborted when NRN_ENABLE_NMODL is ON (or -nmodl). Set NMODL_PYLIB from configure-time PYTHON_LIBRARY and NMODLHOME from the install prefix. Harmless with nocmodl.
|
| WHEN("A random reverse-permutation is applied") { | ||
| std::vector<std::size_t> perm(n); | ||
| std::iota(perm.begin(), perm.end(), 0); | ||
| std::mt19937 g{42}; |
| std::vector<std::size_t> perm(n); | ||
| std::iota(perm.begin(), perm.end(), 0); | ||
| std::mt19937 g{42}; | ||
| std::shuffle(perm.begin(), perm.end(), g); |
Contributor
|
✔️ a49fbad -> artifacts URL |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #3826 +/- ##
==========================================
+ Coverage 68.48% 68.66% +0.18%
==========================================
Files 691 700 +9
Lines 111413 112493 +1080
==========================================
+ Hits 76301 77244 +943
- Misses 35112 35249 +137 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
nrnhines
added a commit
that referenced
this pull request
Jul 26, 2026
NMODL-generated Traub mechs failed to load on NRN_ENABLE_GPU installs with undefined mangled hoc_register_net_send_buffering: GPU defs are extern "C" but public headers declared C++ linkage. Align declarations and CPU stubs. Also refresh GROK-GPU-NATIVE for #3826 absorb, ringtest re-green, and Traub NMODL CPU smoke (4474 spikes @ 100) on this install.
|
✔️ a49fbad -> Azure artifacts URL |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
CPU network SoA heap-free path based on master: Weight SoA is sole storage for NetCon weights; sim-path identity is
weight_indexonly.weight_heap; noSelfEvent::weight_pointerWeightBlockownership; packing A sortweight_bases+_nrn_fornetcon_weight)pnt_receive/net_send/ INITIAL: index ABI (int weight_index, −1 if none)_args[i]via_nrn_netrec_wsoa/_done(zero-copy when contiguous; TLS if scattered)Docs:
doc/network-soa/heap-free.md(steps 1–6, 6b–7c).Includes earlier dual-write / SoA scaffolding from the
local/cpu-network-soaline as intermediate history; the landable product story is heap-free on master, not dual-write alone.Verification
buildctest 225/225build-asanctest 223/223build-nmodl(NRN_ENABLE_NMODL=ON): build OK; network unit +network_soa_delivery+ ringtests OK. Broader NMODL failures are pre-existing NMODL NEURON gaps (WATCH stub, FOR_NETCONS rename order, etc.), not heap-free ABI link failures.Test plan
master)net_send, SaveState/BBSaveState, external FOR_NETCONS (nocmodl path)